package com.chatplus.application.web.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.chatplus.application.web.auditlogger.AuditLogsEntity;
import com.chatplus.application.web.util.IpUtil;
import com.chatplus.application.web.util.ParameterUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.time.Instant;
import java.util.Map;

/**
 * 审计日志拦截器
 *
 * @author chj
 * @date 2022/6/14
 **/
public class AuditLoggerInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(AuditLoggerInterceptor.class);
    //请求开始时间标识
    private static final String LOGGER_SEND_TIME = "AUDIT_LOGGER_SEND_TIME";
    //请求日志实体标识
    private static final String LOGGER_ACCESSING = "AUDIT_LOGGER_ACCESSING_ENTITY";
    // 响应体标识
    public static final String AUDIT_LOGGER_BODY = "AUDIT_LOGGER_BODY";
    //该项目审计日志标识
    private static final String SOURCE = "JAVA";

    public static final String APPLICATION_JSON = "application/json";
    public static final String TEXT_PLAIN = "text/plain";
    public static final String TEXT_HTML = "text/html";

//    @Autowired
//    private TurnRightUser turnRightUser;

    @Autowired
    private ObjectMapper mapper;

    @Autowired
    private UrlFilterUtil urlFilterUtil;

    /**
     * 目标方法执行之前
     */
    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
        try {
            if (urlFilterUtil.excludesURL(request)) {
                return true;
            }
            long start = System.currentTimeMillis();
            String contentType = request.getContentType();
            AuditLogsEntity auditLogsEntity = new AuditLogsEntity();
            // 流数据获取，比如 json
            if (request instanceof IContentCachingRequestWrapper) {
                IContentCachingRequestWrapper requestWrapper = (IContentCachingRequestWrapper) request;
                String body = new String(requestWrapper.getBody(), request.getCharacterEncoding());
                auditLogsEntity.setParameters(body);
            }
            else {
                Map<String, String> parameters = ParameterUtils.toMap(request);
                auditLogsEntity.setParameters(parameters.toString());
            }
            auditLogsEntity.setClientId(request.getHeader("X-CLIENT-ID"));
            auditLogsEntity.setAppVersion(request.getHeader("X-APP-VERSION"));
            auditLogsEntity.setSource(SOURCE);
            auditLogsEntity.setContentType(contentType);
            auditLogsEntity.setClientIpAddress(IpUtil.getRemoteIp(request));
            auditLogsEntity.setExecutionTime(Instant.now());
            auditLogsEntity.setUrl(request.getRequestURI());
            auditLogsEntity.setHttpMethod(request.getMethod());
            //打印method的相关信息
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                // 获取处理当前请求的 handler 信息
                auditLogsEntity.setServiceName(handlerMethod.getBeanType().getName());
                auditLogsEntity.setMethodName(handlerMethod.getMethod().getName());
            }
            //获取浏览器信息
            String uaStr = request.getHeader("user-agent");
            if (!ObjectUtils.isEmpty(uaStr)) {
                auditLogsEntity.setBrowserInfo(uaStr);
            }
            //设置请求实体到request内，方便afterCompletion方法调用
            request.setAttribute(LOGGER_ACCESSING, auditLogsEntity);
            request.setAttribute(LOGGER_SEND_TIME, start);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return true;
        }
    }

    @Override
    public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) {
        try {
            if (urlFilterUtil.excludesURL(request)) {
                return;
            }
            long start = Long.parseLong(request.getAttribute(LOGGER_SEND_TIME).toString());
            long executionDuration = System.currentTimeMillis() - start;

            //获取本次请求日志实体
            AuditLogsEntity auditLogsEntity = (AuditLogsEntity) request.getAttribute(LOGGER_ACCESSING);
            if (ex != null) {
                auditLogsEntity.setException(ex.getMessage());
            }
            Object body = request.getAttribute(AUDIT_LOGGER_BODY);
            if (body != null) {
                String responseBody = mapper.writeValueAsString(body);
                auditLogsEntity.setResponseBody(responseBody);
            }
            auditLogsEntity.setExecutionDuration(executionDuration);

            int status = response.getStatus();
            //已知异常在BaseExceptionAdvice处理了，未知异常没处理，所以这里要特殊处理下
            if (ex != null && HttpStatus.OK.value() == status) {
                status = HttpStatus.INTERNAL_SERVER_ERROR.value();
            }
            auditLogsEntity.setHttpStatus(status);

//            if (turnRightUser != null) {
//                try {
//                    auditLogsEntity.setUserId(turnRightUser.getAccountId());
//                } catch (Exception ignored) {}
//            }
            logger.info(mapper.writeValueAsString(auditLogsEntity));
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
